package cn.org.rookie.jeesdp.core.utils;


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.*;

/**
 * 对象工具类，提供对象转换、序列化和反射等常用方法
 * 包括Map与对象互转、JSON序列化与反序列化、字段获取等功能
 *
 * @author LHT
 */
@Component
public class ObjectUtils extends BaseUtils {

    /**
     * Jackson JSON映射器，用于JSON序列化和反序列化
     */
    private static ObjectMapper mapper;

    /**
     * 将Map转换为指定类型的实体对象
     * 通过反射将Map中的键值对设置到对象的对应字段中
     *
     * @param source 包含属性值的Map，键名为字段名
     * @param type   要转换的目标实体类类型
     * @param <T>    实体类泛型
     * @return 转换后的实体对象
     * @throws RuntimeException 当实例化或字段设置失败时抛出
     */
    public static <T> T populate(Map<String, Object> source, Class<T> type) {
        if (source == null) {
            return null;
        }

        try {
            T instance = type.getConstructor().newInstance();
            for (Field field : getAllField(type)) {
                field.setAccessible(true);
                Object value = source.get(field.getName());
                if (value != null) {
                    field.set(instance, value);
                }
            }
            return instance;
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException |
                 NoSuchMethodException e) {
            throw new RuntimeException("Map转实体对象失败: " + type.getName(), e);
        }
    }

    /**
     * 将对象转换为Map
     * 通过反射获取对象的所有字段及其值，并存储在LinkedHashMap中保持字段顺序
     *
     * @param bean 要转换的对象
     * @return 包含所有字段名和字段值的Map
     * @throws RuntimeException 当字段访问失败时抛出
     */
    public static Map<String, Object> describe(Object bean) {
        if (bean == null) {
            return new LinkedHashMap<>();
        }

        Map<String, Object> map = new LinkedHashMap<>();

        getAllField(bean.getClass()).forEach(field -> {
            try {
                field.setAccessible(true);
                map.put(field.getName(), field.get(bean));
            } catch (IllegalAccessException e) {
                throw new RuntimeException("对象转Map失败: " + field.getName(), e);
            }
        });
        return map;
    }

    /**
     * 获取指定类的所有字段，包括继承自父类的字段
     * 采用递归方式获取整个类层次结构中的所有字段
     *
     * @param type 实体类的类型
     * @return 包含所有字段的列表，父类字段在前，子类字段在后
     */
    public static List<Field> getAllField(Class<?> type) {
        if (type == null) {
            return new ArrayList<>();
        }

        List<Field> fields = new ArrayList<>();

        // 递归获取父类字段
        Class<?> superclass = type.getSuperclass();
        if (superclass != null && !superclass.equals(Object.class)) {
            fields.addAll(getAllField(superclass));
        }

        // 添加当前类声明的字段
        fields.addAll(Arrays.asList(type.getDeclaredFields()));
        return fields;
    }

    /**
     * 将对象转换为表单格式字符串
     * 支持处理数组、集合和单个值的字段
     *
     * @param obj 要转换的对象
     * @return 表单格式字符串，格式为key1=value1&key2=value2...
     * @throws RuntimeException 当字段访问失败时抛出
     */
    public static String toFormString(Object obj) {
        if (obj == null) {
            return "";
        }

        StringBuilder sb = new StringBuilder();

        getAllField(obj.getClass()).forEach(field -> {
            try {
                field.setAccessible(true);
                Object value = field.get(obj);
                if (value != null) {
                    Object[] values;

                    // 处理不同类型的值
                    if (value instanceof List || value instanceof Set) {
                        values = ((Collection<?>) value).toArray();
                    } else if (value instanceof Object[]) {
                        values = (Object[]) value;
                    } else {
                        values = new Object[]{value};
                    }

                    // 根据值的数量生成不同的表单格式
                    if (values.length > 1) {
                        // 数组格式：key[0]=value0&key[1]=value1
                        for (int i = 0; i < values.length; i++) {
                            sb.append(String.format("%s[%s]=%s&", field.getName(), i, values[i]));
                        }
                    } else if (values.length == 1) {
                        // 单值格式：key=value
                        sb.append(String.format("%s=%s&", field.getName(), values[0]));
                    }
                }
            } catch (IllegalAccessException e) {
                throw new RuntimeException("对象转表单字符串失败: " + field.getName(), e);
            }
        });

        // 移除末尾的&符号
        if (!sb.isEmpty()) {
            return sb.substring(0, sb.length() - 1);
        }
        return "";
    }

    /**
     * 将对象序列化为JSON字符串
     * 使用默认配置的ObjectMapper进行序列化
     *
     * @param obj 要序列化的对象
     * @return JSON字符串
     * @throws RuntimeException 当序列化失败时抛出
     */
    public static String toJsonString(Object obj) {
        if (obj == null) {
            return null;
        }
        try {
            return mapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("对象序列化为JSON失败", e);
        }
    }

    /**
     * 将对象序列化为格式化的JSON字符串
     * 启用缩进输出，使JSON更易读
     *
     * @param obj 要序列化的对象
     * @return 格式化的JSON字符串
     * @throws RuntimeException 当序列化失败时抛出
     */
    public static String toIndentedJsonString(Object obj) {
        if (obj == null) {
            return null;
        }
        try {
            // 临时启用缩进输出
            mapper.enable(SerializationFeature.INDENT_OUTPUT);
            String jsonString = mapper.writeValueAsString(obj);
            // 恢复默认设置
            mapper.disable(SerializationFeature.INDENT_OUTPUT);
            return jsonString;
        } catch (JsonProcessingException e) {
            throw new RuntimeException("对象序列化为格式化JSON失败", e);
        }
    }

    /**
     * 将JSON字节数组反序列化为指定类型的对象
     *
     * @param json JSON字节数组
     * @param type 目标对象类型
     * @param <T>  对象类型泛型
     * @return 反序列化后的对象
     * @throws RuntimeException 当反序列化失败时抛出
     */
    public static <T> T toObject(byte[] json, Class<T> type) {
        if (json == null) {
            return null;
        }
        try {
            return mapper.readValue(json, type);
        } catch (IOException e) {
            throw new RuntimeException("JSON字节数组反序列化失败: " + type.getName(), e);
        }
    }

    /**
     * 将JSON字符串反序列化为指定类型的对象
     *
     * @param json JSON字符串
     * @param type 目标对象类型
     * @param <T>  对象类型泛型
     * @return 反序列化后的对象
     * @throws RuntimeException 当反序列化失败时抛出
     */
    public static <T> T toObject(String json, Class<T> type) {
        if (json == null || json.isEmpty()) {
            return null;
        }
        return toObject(json.getBytes(), type);
    }

    /**
     * 将JSON字符串反序列化为指定类型的对象列表
     *
     * @param json JSON字符串
     * @param type 列表元素类型
     * @param <T>  元素类型泛型
     * @return 反序列化后的对象列表
     * @throws RuntimeException 当反序列化失败时抛出
     */
    public static <T> List<T> toObjectList(String json, Class<T> type) {
        if (json == null || json.isEmpty()) {
            return new ArrayList<>();
        }
        return toObjectList(json.getBytes(), type);
    }

    /**
     * 将JSON字节数组反序列化为指定类型的对象列表
     *
     * @param json JSON字节数组
     * @param type 列表元素类型
     * @param <T>  元素类型泛型
     * @return 反序列化后的对象列表
     * @throws RuntimeException 当反序列化失败时抛出
     */
    public static <T> List<T> toObjectList(byte[] json, Class<T> type) {
        if (json == null) {
            return new ArrayList<>();
        }
        try {
            return mapper.readValue(json, getCollectionType(type));
        } catch (IOException e) {
            throw new RuntimeException("JSON字节数组反序列化为列表失败: " + type.getName(), e);
        }
    }

    /**
     * 将JSON字符串解析为JsonNode对象
     * JsonNode提供了灵活的树模型，便于对JSON进行读取和修改
     *
     * @param json JSON字符串
     * @return JsonNode对象，可用于遍历JSON结构
     * @throws RuntimeException 当JSON解析失败时抛出
     */
    public static JsonNode toJsonNode(String json) {
        if (json == null || json.isEmpty()) {
            return null;
        }
        try {
            return mapper.readTree(json);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("JSON字符串解析为JsonNode失败", e);
        }
    }

    /**
     * 将Java对象转换为JsonNode对象
     * 便于将对象转换为可操作的JSON树结构
     *
     * @param obj 要转换的Java对象
     * @return JsonNode对象，表示该对象的JSON结构
     */
    public static JsonNode toJsonNode(Object obj) {
        if (obj == null) {
            return null;
        }
        return mapper.valueToTree(obj);
    }

    /**
     * 构造泛型集合的JavaType
     * 用于Jackson反序列化时指定具体的泛型类型
     *
     * @param elementClasses 集合元素的类型
     * @return 表示List<T>类型的JavaType对象
     */
    private static JavaType getCollectionType(Class<?>... elementClasses) {
        return mapper.getTypeFactory().constructParametricType(List.class, elementClasses);
    }

    /**
     * 初始化方法，从Spring容器获取ObjectMapper实例
     * 实现InitializingBean接口，在Bean属性设置完成后被调用
     */
    @Override
    public void afterPropertiesSet() {
        mapper = applicationContext.getBean(ObjectMapper.class);
    }
}
